package com.novel.authorization.staff.controller;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.novel.authorization.constant.UserStatusEnum;
import com.novel.authorization.staff.entity.NfUser;
import com.novel.authorization.staff.service.NfUserService;
import com.novel.authorization.staff.vo.UserInfoVO;
import com.novel.authorization.tenant.TenantContextHolder;
import com.novel.authorization.vip.VipContextHolder;
import com.novel.base.constants.CommonConstants;
import com.novel.base.entity.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

/**
 * AuthController
 *
 * @author 樊温军
 * @date 2025/5/6 下午5:50
 */
@Slf4j
@RestController
@RequestMapping("/auth")
@Api(tags = "权限控制器")
@RequiredArgsConstructor
public class AuthController {

    private final RedisTemplate<String, Object> redisTemplate;
    private final NfUserService nfUserService;

    /**
     * 用户—登录
     *
     * @return R<SaTokenInfo>
     */
    @PostMapping("/login")
    @ApiOperation(value = "用户—登录")
    public R<SaTokenInfo> login(@RequestBody Map<String, String> params) {
        String uname = MapUtil.getStr(params, "uname");
        String pwd = MapUtil.getStr(params, "pwd");
        String tenantId = MapUtil.getStr(params, "tenantId");
        boolean remember = MapUtil.getBool(params, "remember", false);
        if (ObjUtil.isEmpty(uname)) {
            return R.failed("用户名不能为空！");
        }
        if (ObjUtil.isEmpty(pwd)) {
            return R.failed("密码不能为空！");
        }
        if (ObjUtil.isEmpty(tenantId)) {
            return R.failed("请给出租户ID！");
        }
        TenantContextHolder.setTenantId(tenantId);
        NfUser user = nfUserService.getOne(Wrappers.<NfUser>lambdaQuery().eq(NfUser::getUname, uname));
        R<Boolean> r = checkAuth(user, pwd);
        if (!r.getData()) {
            return R.failed(r.getMessage());
        }
        redisTemplate.opsForValue().set(CommonConstants.VIP_SESSION_KEY + ":" + user.getId(), user.getVip());
        UserInfoVO userInfoVO = nfUserService.getUserInfo(user);
        StpUtil.login(user.getId(), remember);
        StpUtil.getSession().set(CommonConstants.USER_SESSION_KEY, userInfoVO);
        // 更新最后登录时间
        nfUserService.update(Wrappers.<NfUser>lambdaUpdate().set(NfUser::getLastLogin, LocalDateTime.now()).eq(NfUser::getId, user.getId()));
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return R.ok(tokenInfo);
    }

    private static R<Boolean> checkAuth(NfUser user, String pwd) {
        if (Objects.isNull(user)) {
            return R.failed(Boolean.FALSE, "用户不存在！");
        }
        VipContextHolder.setVip(user.getVip());
        if (UserStatusEnum.NON_AUTH.getCode().equals(user.getStatus())) {
            return R.failed(Boolean.FALSE, "账号未认证，请先认证！");
        }
        if (UserStatusEnum.LOCKED.getCode().equals(user.getStatus())) {
            return R.failed(Boolean.FALSE, "账号已锁定，请联系管理员！");
        }
        if (UserStatusEnum.LOGOUT.getCode().equals(user.getStatus())) {
            return R.failed(Boolean.FALSE, "账号已注销，请联系管理员！");
        }
        if (!ObjUtil.isEmpty(user.getEffectTime()) && user.getEffectTime().isAfter(LocalDateTime.now())) {
            return R.failed(Boolean.FALSE, "账号还未生效，请联系管理员！");
        }
        if (!ObjUtil.isEmpty(user.getExpireTime()) && user.getExpireTime().isBefore(LocalDateTime.now())) {
            return R.failed(Boolean.FALSE, "账号已过期，请联系管理员！");
        }
        String plaintext = SaSecureUtil.aesDecrypt(user.getSalt() + user.getId(), user.getPwd());
        if (!plaintext.equals(pwd)) {
            return R.failed(Boolean.FALSE, "密码错误！");
        }
        return R.ok(Boolean.TRUE, "校验通过！");
    }

    /**
     * 用户—注销
     *
     * @return R<Boolean>
     */
    @PostMapping("/logout")
    @ApiOperation(value = "用户—注销")
    public R<Boolean> logout() {
        if (StpUtil.isLogin()) {
            StpUtil.getSession().clear();
            StpUtil.logout();
        }
        return R.ok(Boolean.TRUE, "注销成功！");
    }

}
